---
title: Recording (Beta)
---
import Tabs from '@theme/Tabs';
import TabItem from '@theme/TabItem';

With LiveKit Recorder, you can record your session for livestreaming or archival. LiveKit Recorder runs Chrome underneath, which allows you to customize recording layout however you'd like. In many cases, you could leverage your application's existing Room UI with little change. We also provide a couple of pre-built recording views, a `speaker` layout and `grid` layout.

The recorder can output the session to a file, S3 object, or Azure blob storage (as an mp4). If you are planning to livestream the session, it can be streamed to one or multiple RTMP endpoints.

![Recorder architecture](/img/recorder/recorder-architecture.svg)

## Standalone

Start recording in seconds with our standalone recorder. The recorder is published as a [docker image](https://hub.docker.com/r/livekit/livekit-recorder), and can be used with no setup required.

Try the quick start demo below, and find all the recording options along with more in-depth examples [here](https://github.com/livekit/livekit-recorder).

### Quick start

Start by filling in a `config.yaml`:
```
api_key: <livekit-server-api-key>
api_secret: <livekit-server-api-secret>
ws_url: <livekit-server-ws-url>
file_output:
    local: true
```

Next, create a `request.json`:
```json
{
  "url": "https://www.youtube.com/watch?v=dQw4w9WgXcQ",
  "filepath": "/out/demo.mp4"
}
```

Start the recording:
```shell
mkdir -p ~/livekit/recordings
docker run --rm --name demo \
    -e LIVEKIT_RECORDER_CONFIG="$(cat config.yaml)" \
    -e RECORDING_REQUEST="$(cat basic.json)" \
    -v ~/livekit/recordings:/out \
    livekit/livekit-recorder
```

Then, to stop the recording:
```shell
docker stop demo
```

You should find a `~/livekit/recordings/demo.mp4`.

## Service

While standalone mode is easy to get started, you may want to [deploy](/guides/deploy/recorder) the recorder as a service for programmatic access to recording.
Once deployed, rooms can be recorded by indicating as such during room creation.

![Recorder service](/img/recorder/recorder-service.svg)

In this mode, recorder service instances listen to Redis for recording jobs requested by LiveKit server.
Only one instance of the service will be assigned to a single job.
You can start multiple instances of the service to ensure spare capacity when rooms need to be recorded.

### Start a recording

To record a webpage, use the `Url` recording input instead of `Template`.

<Tabs
    defaultValue="node"
    groupId="server-sdk"
    values={[
        {label: 'Node', value: 'node'},
        {label: 'Golang', value: 'go'},
        {label: 'Cli', value: 'cli'},
    ]}>
  <TabItem value="node">

```typescript title="TypeScript"
const input = {
    template: {
        layout: 'grid-dark',
        room_name: 'my-room'
    }
}
const output = {
    filepath: "path/recording.mp4"
}
const recordingClient = NewRecordingServiceClient("https://your-livekit-host", "livekit-api-key", "livekit-api-secret");
const recordingId = await recordingClient.startRecording(input, output)
```

  </TabItem>

  <TabItem value="go">

```go title="Go"
req := &livekit.StartRecordingRequest{
    Input: &livekit.StartRecordingRequest_Template{
        Template: &livekit.RecordingTemplate{
            Layout: "speaker-dark",
            RoomName: "my-room",
        },
    },
    Output: &livekit.StartRecordingRequest_Filepath{
        Filepath: "path/test.mp4",
    },
}

recordingClient := NewRecordingServiceClient("https://yourlivekit-host", "livekit-api-key", "livekit-api-secret")
resp, err := recordingClient.StartRecording(context.Background(), req)
recordingID := resp.RecordingId
```

  </TabItem>

  <TabItem value="cli">

```bash
livekit-cli start-recording \
      --url https://your-livekit-address.com \
      --api-key livekit-api-key \
      --api-secret livekit-api-secret \
      --request request.json
```
Prints your recording ID:
```
Recording started. Recording ID: RR_XXXXXXXXXXXX
```

  </TabItem>

</Tabs>

### Add or remove outputs

Note: you can only add or remove outputs from a stream (rtmp output instead of filepath).

<Tabs
    defaultValue="node"
    groupId="server-sdk"
    values={[
        {label: 'Node', value: 'node'},
        {label: 'Golang', value: 'go'},
        {label: 'Cli', value: 'cli'},
    ]}>
  <TabItem value="node">

```typescript title="TypeScript"
recordingClient.addOutput(recordingId, "rtmp://output-url");
recordingClient.removeOutput(recordingId, "rtmp://output-url");
```

  </TabItem>

  <TabItem value="go">

```go title="Go"
addRequest := &livekit.AddOutputRequest{
    RecordingId: recordingID,
    RtmpUrl: "rtmp://output-url",
}
_, err := recordingClient.AddOutput(context.Background(), addRequest)

removeRequest := &livekit.RemoveOutputRequest{
    RecordingId: recordingID,
    RtmpUrl: "rtmp://output-url",
}
_, err := recordingClient.RemoveOutput(context.Background(), removeRequest)
```

  </TabItem>

  <TabItem value="cli">

```bash
livekit-cli add-output \
    --url https://your-livekit-address.com \
    --api-key livekit-api-key \
    --api-secret livekit-api-secret \
    --id RR_XXXXXXXXXXXX \
    --rtmp-url "rtmp://output-url"

livekit-cli remove-output \
    --url https://your-livekit-address.com \
    --api-key livekit-api-key \
    --api-secret livekit-api-secret \
    --id RR_XXXXXXXXXXXX \
    --rtmp-url "rtmp://output-url"
```

  </TabItem>

</Tabs>

### End a recording

<Tabs
    defaultValue="node"
    groupId="server-sdk"
    values={[
        {label: 'Node', value: 'node'},
        {label: 'Golang', value: 'go'},
        {label: 'Cli', value: 'cli'},
    ]}>
  <TabItem value="node">

```typescript title="TypeScript"
recordingClient.endRecording(recordingId);
```

  </TabItem>

  <TabItem value="go">

```go title="Go"
req := &livekit.EndRecordingRequest{
    RecordingId: recordingID,
}
_, err := recordingClient.EndRecording(context.Background(), req)
```

  </TabItem>

  <TabItem value="cli">

```bash
livekit-cli end-recording \
      --url https://your-livekit-address.com \
      --api-key livekit-api-key \
      --api-secret livekit-api-secret \
      --id RR_XXXXXXXXXXXX
```

  </TabItem>

</Tabs>

## Creating your own templates

You likely already have a room UI built with LiveKit web SDKs. The recording UI can be similar to your existing room UI, with a few differences:

- Do not render the local participant - in this case, the local participant will be the recorder instance
- Token permissions - the recorder should have `canSubscribe` and `hidden` set to true
- Room controls (mute, leave, etc) should not be visible

Source code to our default room templates, and more info can be [found here](https://github.com/livekit/livekit-recorder/tree/main/web).
